/****************************************************************
 * Fulguro
 * Copyright (C) 2004 Christophe Clienti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 ***************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "flgrCoreMalloc.h"
#include "flgrCoreData.h"
#include "flgrCoreCopy.h"
#include "flgrCoreDataIO.h"
#include "flgrCoreDispatch.h"
#include "flgrCoreNhbFill.h"


/*!
 * \defgroup group_fulguro_core Core
 *
 * This module is the main part of the library and define all data types, error codes,
 * and allocating/free functions.
 * <BR>
 * Core module aims to give a common part to all others modules in order
 * to avoid code rewriting, to preserve stability and to give a common interface.
 * <BR>
 * Allocating function are redefine to test if allocations are correctly done.
 * <BR>
 * Macro to display Errors, Warning, Information works as a standard printf but print the calling function
 * name before anything else given by the user.
 * This Macro must used to debug information and in a near future,
 * complete error tracing will be made thanks to POST_ERROR and POST_WARNING
 *
 *
 *
 *
 * \defgroup group_fulguro_core_array Array Manipulation
 * \ingroup group_fulguro_core
 * \brief Main functions to allocate and manipulate 2D Array
 * @{
 */


//////////////////////////////////////////////////////////////////
/*! Protect coordinate access as the image was unfolded
 *  @param axis_coord  : coordinate value of an axis
 *  @param axis_length : axis length
 *  @returns new coord
 */
//////////////////////////////////////////////////////////////////
int flgr_normalize_coordinate(int axis_coord, int axis_length) {
  int axis_true = (-1*axis_coord-1);
  int axis_false;
  int axis_test;

  FLGR_DECLARE_FUNCTION;

  axis_coord = ((axis_coord<0) ? (axis_true) : axis_coord);

  axis_test = ((axis_coord/axis_length)%2);
  axis_true = axis_length - (axis_coord%axis_length) - 1;
  axis_false = axis_coord%axis_length;

  axis_coord = ((axis_coord>=axis_length) && (axis_test)) ? (axis_true) : (axis_coord);
  axis_coord = ((axis_coord>=axis_length) && !(axis_test)) ? (axis_false) : (axis_coord);

/*   if(axis_coord<0) { */
/*     axis_coord=-1*axis_coord-1; */
/*   } */

/*   if( axis_coord >= axis_length ) { */
/*     if( ((axis_coord/axis_length)%2) == 1 ) */
/*       axis_coord = axis_length - (axis_coord%axis_length) - 1; */
/*     else */
/*       axis_coord = axis_coord%axis_length; */
/*   } */

  return axis_coord;
}






//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
// 1D FUNCTIONS
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////

#define FLGR_MACRO_CREATE1D(dtype, dtypename)				\
  FLGR_Data1D *dat;							\
  FLGR_DECLARE_FUNCTION;						\
									\
  if(length<0) {							\
    POST_ERROR("Negative length!\n");					\
    return NULL;							\
  }									\
  if(spp<1) {								\
    POST_ERROR("Sample Per Pixel (spp) must be > 0 !\n");		\
    return NULL;							\
  }									\
  dat = (FLGR_Data1D*) flgr_malloc(sizeof(FLGR_Data1D));		\
  dat->dim = 1;								\
  dat->size_struct = sizeof(FLGR_Data1D);				\
  dat->bps = flgr_get_bps_from_type(dtypename);				\
  dat->ref2d = -1;							\
  dat->shape = shape;							\
  dat->spp   = spp;							\
  dat->length = length;							\
  dat->array_phantom = flgr_malloc_align((length*dat->bps*spp)/8+64,16);\
  dat->array = dat->array_phantom+32;					\
  dat->type = dtypename;						\
									\
  return dat


FLGR_Data1D *flgr1d_create_fgBIT(int length, int spp, FLGR_Shape shape) {
  FLGR_MACRO_CREATE1D(fgBIT, FLGR_BIT);
}
FLGR_Data1D *flgr1d_create_fgUINT8(int length, int spp, FLGR_Shape shape) {
  FLGR_MACRO_CREATE1D(fgUINT8, FLGR_UINT8);
}
FLGR_Data1D *flgr1d_create_fgUINT16(int length, int spp, FLGR_Shape shape) {
  FLGR_MACRO_CREATE1D(fgUINT16, FLGR_UINT16);
}
FLGR_Data1D *flgr1d_create_fgUINT32(int length, int spp, FLGR_Shape shape) {
  FLGR_MACRO_CREATE1D(fgUINT32, FLGR_UINT32);
}
FLGR_Data1D *flgr1d_create_fgINT8(int length, int spp, FLGR_Shape shape) {
  FLGR_MACRO_CREATE1D(fgINT8, FLGR_INT8);
}
FLGR_Data1D *flgr1d_create_fgINT16(int length, int spp, FLGR_Shape shape) {
  FLGR_MACRO_CREATE1D(fgINT16, FLGR_INT16);
}
FLGR_Data1D *flgr1d_create_fgINT32(int length, int spp, FLGR_Shape shape) {
  FLGR_MACRO_CREATE1D(fgINT32, FLGR_INT32);
}
FLGR_Data1D *flgr1d_create_fgFLOAT32(int length, int spp, FLGR_Shape shape) {
  FLGR_MACRO_CREATE1D(fgFLOAT32, FLGR_FLOAT32);
}
FLGR_Data1D *flgr1d_create_fgFLOAT64(int length, int spp, FLGR_Shape shape) {
  FLGR_MACRO_CREATE1D(fgFLOAT64, FLGR_FLOAT64);
}

//////////////////////////////////////////////////////////////////
/*! Allocate a FLGR_Data1D structure
 *  @param length    : an integer for array length
 *  @param type      : a string for data type
 *  @param spp       : Samples per pixel
 *  @param shape     : shape
 *  @returns FLGR_Data1D pointer
 */
//////////////////////////////////////////////////////////////////
FLGR_Data1D *flgr1d_create(int length, int spp, FLGR_Type type, FLGR_Shape shape) {

  FLGR_DECLARE_FUNCTION;

  if(type==FLGR_BIT) return flgr1d_create_fgBIT(length, spp, shape);
  if(type==FLGR_UINT8) return flgr1d_create_fgUINT8(length, spp, shape);
  if(type==FLGR_UINT16) return flgr1d_create_fgUINT16(length, spp, shape);
  if(type==FLGR_UINT32) return flgr1d_create_fgUINT32(length, spp, shape);
  if(type==FLGR_INT8) return flgr1d_create_fgINT8(length, spp, shape);
  if(type==FLGR_INT16) return flgr1d_create_fgINT16(length, spp, shape);
  if(type==FLGR_INT32) return flgr1d_create_fgINT32(length, spp, shape);
  if(type==FLGR_FLOAT32) return flgr1d_create_fgFLOAT32(length, spp, shape);
  if(type==FLGR_FLOAT64) return flgr1d_create_fgFLOAT64(length, spp, shape);

  POST_ERROR("Type unknown!\n");
  return NULL;
}

//////////////////////////////////////////////////////////////////
/*! Allocate a FLGR_Data1D structure from another one. Just allocation is performed, no copy.
 *  @param dat : FLGR_Data1D pointer
 *  @returns FLGR_Data1D pointer
 */
//////////////////////////////////////////////////////////////////
FLGR_Data1D *flgr1d_create_from(FLGR_Data1D *dat) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return NULL;
  }
  return flgr1d_create(dat->length, dat->spp, dat->type, dat->shape);
}

//////////////////////////////////////////////////////////////////
/*! Allocate a FLGR_Data1D structure
 *  @param length    : an integer for array length
 *  @param spp       : Samples per pixel
 *  @param type      : a string for data type
 *  @returns FLGR_Data1D pointer
 */
//////////////////////////////////////////////////////////////////
FLGR_Data1D *flgr1d_create_signal(int length, int spp, FLGR_Type type) {
  FLGR_DECLARE_FUNCTION;

  return flgr1d_create(length, spp, type, FLGR_NO_SHAPE);
}

//////////////////////////////////////////////////////////////////
/*! Allocate a FLGR_Data1D structure from another one. Just allocation is performed, no copy.
 *  @param dat : FLGR_Data1D pointer
 *  @returns FLGR_Data1D pointer
 */
//////////////////////////////////////////////////////////////////
FLGR_Data1D *flgr1d_create_signal_from(FLGR_Data1D *dat) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return NULL;
  }
  return flgr1d_create(dat->length, dat->spp, dat->type, FLGR_NO_SHAPE);
}

//////////////////////////////////////////////////////////////////
/*! Allocate a FLGR_Data1D structure representing a neighborhood.
 *  @param length    : an integer for array length
 *  @param type      : a string for data type
 *  @param shape     : shape
 *  @param spp       : Samples Per Pixel
 *  @returns FLGR_Data1D pointer
 */
//////////////////////////////////////////////////////////////////
FLGR_Data1D *flgr1d_create_neighborhood(int length, int spp, FLGR_Type type, FLGR_Shape shape) {
  FLGR_Data1D *tmp;
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  tmp = flgr1d_create(length, spp, type, shape);

  if(tmp == NULL) return NULL;

  ret = flgr1d_fill_neighborhood(tmp,shape,length);

  if(ret != FLGR_RET_OK) {
    POST_ERROR("Could not fill the nhb definition\n");
    flgr1d_destroy(tmp);
    return NULL;
  }

  return tmp;

}

//////////////////////////////////////////////////////////////////
/*! Allocate a FLGR_Data1D structure representing a neighborhood from another one
 *  @param dat : FLGR_Data1D pointer
 *  @returns FLGR_Data1D pointer
 */
//////////////////////////////////////////////////////////////////
FLGR_Data1D *flgr1d_create_neighborhood_from(FLGR_Data1D *dat) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return NULL;
  }
  return flgr1d_create_neighborhood(dat->length,dat->spp,dat->type,dat->shape);
}


//////////////////////////////////////////////////////////////////
/*! Unallocate a FLGR_Data1D structure
 *  @param dat : a pointer to FLGR_Data1D
 *  @returns FLGR_Data1D
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_destroy(FLGR_Data1D *dat) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  flgr_free_align(dat->array_phantom);
  flgr_free(dat);

  return FLGR_RET_OK;
}

//////////////////////////////////////////////////////////////////
/*! Test if data1d have same length
 *  @param dat1 : a pointer to FLGR_Data1D
 *  @param dat2 : a pointer to FLGR_Data1D
 *  @returns Return FLGR_RET_OK, FLGR_RET_SIZE_ERROR
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_is_data_same_length(FLGR_Data1D *dat1, FLGR_Data1D *dat2) {
  FLGR_DECLARE_FUNCTION;

  if((dat1==NULL) || (dat2==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((dat1->length!=dat2->length)) {
    return FLGR_RET_SIZE_ERROR;
  }
  return FLGR_RET_OK;
}

//////////////////////////////////////////////////////////////////
/*! Test if data1d have same type and same samples per pixel. 
 *  Valid type check is also performed
 *  @param dat1 : a pointer to FLGR_Data1D
 *  @param dat2 : a pointer to FLGR_Data1D
 *  @returns Return FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_is_data_same_type(FLGR_Data1D *dat1, FLGR_Data1D *dat2) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((dat1==NULL) || (dat2==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }


  if((ret=flgr_is_data_type_valid(dat1->type))!=FLGR_RET_OK) return ret;
  if((ret=flgr_is_data_type_valid(dat2->type))!=FLGR_RET_OK) return ret;

  if(dat1->type != dat2->type) return FLGR_RET_TYPE_DIFFERENT;

  return FLGR_RET_OK;
}

//////////////////////////////////////////////////////////////////
/*! Test if data1d have same samples per pixel. 
 *  Valid spp check is also performed
 *  @param dat1 : a pointer to FLGR_Data1D
 *  @param dat2 : a pointer to FLGR_Data1D
 *  @returns Return FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_is_data_same_spp(FLGR_Data1D *dat1, FLGR_Data1D *dat2) {
  FLGR_DECLARE_FUNCTION;

  if((dat1==NULL) || (dat2==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }


  if(dat1->spp <0) return  FLGR_RET_VECTOR_SIZE_DIFFERENT;
  if(dat2->spp <0) return FLGR_RET_VECTOR_SIZE_DIFFERENT;

  if(dat1->spp != dat2->spp) return FLGR_RET_VECTOR_SIZE_DIFFERENT;

  return FLGR_RET_OK;
}


//////////////////////////////////////////////////////////////////
/*! Test if two FLGR_Data2D have the same sizes and same types
 *  @param data1 : a pointer to FLGR_Data1D
 *  @param data2 : a pointer to FLGR_Data1D
 *  @param callingFunction : String representing the name of the calling function
 *  @returns FLGR_RET_OK, FLGR_RET_SIZE_ERROR, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_is_data_same_attributes(FLGR_Data1D *data1, FLGR_Data1D *data2, const char *callingFunction) {
  FLGR_Ret ret;
 
  FLGR_DECLARE_FUNCTION;


  if((data1==NULL) || (data2==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if( (ret=flgr_is_data_type_valid(data1->type))!=FLGR_RET_OK) {
    EPRINTF("%s: unknown type\r\n", callingFunction);
    return ret;
  }

  if( (ret=flgr_is_data_type_valid(data2->type))!=FLGR_RET_OK) {
    EPRINTF("%s: unknown type\r\n", callingFunction);
    return ret;
  }

  if((ret=flgr1d_is_data_same_type(data1, data2))!=FLGR_RET_OK) {
    EPRINTF("%s : source and destination have a different type\r\n", callingFunction);
    return ret;
  }

  if((ret=flgr1d_is_data_same_spp(data1, data2))!=FLGR_RET_OK) {
    EPRINTF("%s : source and destination have a different vector size (spp)\r\n", callingFunction);
    return ret;
  }

  if((ret=flgr1d_is_data_same_length(data1, data2))!=FLGR_RET_OK) {
    EPRINTF("%s : source and destination have a different size\r\n", callingFunction);
    return ret;
  }

  return FLGR_RET_OK;
}


//////////////////////////////////////////////////////////////////
/*! Test if a FLGR_Data1D correspond to a given shape
 *  @param data : a pointer to FLGR_Data1D
 *  @param shape
 *  @returns boolean
 */
//////////////////////////////////////////////////////////////////
int flgr1d_data_is_shape(FLGR_Data1D *data, FLGR_Shape shape) {
  FLGR_DECLARE_FUNCTION;

  if(data==NULL) {
    POST_ERROR("Null objects!\n");
    return 0;
  }
  return (data->shape==shape);
}


int flgr1d_data_is_type_fgBIT(FLGR_Data1D *data) {
  return (data->type==FLGR_BIT);
}
int flgr1d_data_is_type_fgUINT8(FLGR_Data1D *data) {
  return (data->type==FLGR_UINT8);
}
int flgr1d_data_is_type_fgUINT16(FLGR_Data1D *data) {
  return (data->type==FLGR_UINT16);
}
int flgr1d_data_is_type_fgUINT32(FLGR_Data1D *data) {
  return (data->type==FLGR_UINT32);
}
int flgr1d_data_is_type_fgINT8(FLGR_Data1D *data) {
  return (data->type==FLGR_INT8);
}
int flgr1d_data_is_type_fgINT16(FLGR_Data1D *data) {
  return (data->type==FLGR_INT16);
}
int flgr1d_data_is_type_fgINT32(FLGR_Data1D *data) {
  return (data->type==FLGR_INT32);
}
int flgr1d_data_is_type_fgFLOAT32(FLGR_Data1D *data) {
  return (data->type==FLGR_FLOAT32);
}
int flgr1d_data_is_type_fgFLOAT64(FLGR_Data1D *data) {
  return (data->type==FLGR_FLOAT64);
}
//////////////////////////////////////////////////////////////////
/*! Test if a FLGR_Data1D correspond to a given type
 *  @param data : a pointer to FLGR_Data1D
 *  @param type : type
 *  @returns boolean
 */
//////////////////////////////////////////////////////////////////
int flgr1d_data_is_type(FLGR_Data1D *data, FLGR_Type type) {
  FLGR_DECLARE_FUNCTION;

  if(data==NULL) {
    POST_ERROR("Null objects!\n");
    return 0;
  }
  FLGR_DISPATCH_FUNCTION(FLGR_FALSE,type,flgr1d_data_is_type,data);
}

//////////////////////////////////////////////////////////////////
/*! Change the shape string of a FLGR_Data2D (No modification of neighborhood definition or pixel array)
 *  @param dat : a pointer to FLGR_Data2D
 *  @param shape : a string for shape
 *  @returns nothing
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_data_set_shape(FLGR_Data1D *dat, FLGR_Shape shape) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  dat->shape = shape;

  return FLGR_RET_OK;
}


//////////////////////////////////////////////////////////////////
/*! Set to zero the whole image
 *  @param data : a pointer to a FLGR_Data1D
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_clear_all(FLGR_Data1D *data) {
  FLGR_DECLARE_FUNCTION;

  if(data==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  memset(data->array, 0, (data->length*data->bps*data->spp)/8+32);
  return FLGR_RET_OK;
}












//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
// 2D FUNCTIONS
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////


#define FLGR_MACRO_CREATE2D(dtype, dtypename)				\
  int i;								\
  FLGR_Data2D *dat;							\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  if(size_y<0) {							\
    POST_ERROR("Number of rows is negative !\n");			\
    return NULL;							\
  }									\
									\
  if(size_x<0) {							\
    POST_ERROR("Number of columns is negative !\n");			\
    return NULL;							\
  }									\
									\
  if(spp<1) {								\
    POST_ERROR("Sample Per Pixel (spp) must be > 0 !\n");		\
    return NULL;							\
  }									\
									\
  dat = (FLGR_Data2D*) flgr_malloc(sizeof(FLGR_Data2D));		\
  dat->row = (FLGR_Data1D**) flgr_malloc((size_y+16)*			\
					 sizeof(FLGR_Data1D*));		\
  dat->array = flgr_malloc((size_y+16)*sizeof(dtype*));			\
  dat->dim = 2;								\
  dat->size_struct = sizeof(FLGR_Data2D);				\
  dat->bps = flgr_get_bps_from_type(dtypename);				\
  dat->spp = spp;							\
  dat->shape = shape;							\
  dat->connexity = connexity;						\
  dat->size_y=size_y;							\
  dat->size_x=size_x;							\
  dat->type = dtypename;						\
  dat->link_overlap = -1;						\
  dat->link_position = -1;						\
  dat->link_number = -1;						\
									\
  for(i=0;i<(size_y+16);i++) {						\
    dat->row[i] = flgr1d_create_##dtype(size_x, spp,FLGR_NO_SHAPE);	\
    dat->row[i]->ref2d = i;						\
    dat->array[i] = dat->row[i]->array;					\
  }									\
									\
  return dat

FLGR_Data2D *flgr2d_create_fgBIT(int size_y, int size_x, int spp, FLGR_Shape shape, FLGR_Connexity connexity) {
  FLGR_MACRO_CREATE2D(fgBIT, FLGR_BIT);
}
FLGR_Data2D *flgr2d_create_fgUINT8(int size_y, int size_x, int spp, FLGR_Shape shape, FLGR_Connexity connexity) {
  FLGR_MACRO_CREATE2D(fgUINT8, FLGR_UINT8);
}
FLGR_Data2D *flgr2d_create_fgUINT16(int size_y, int size_x, int spp, FLGR_Shape shape, FLGR_Connexity connexity) {
  FLGR_MACRO_CREATE2D(fgUINT16, FLGR_UINT16);
}
FLGR_Data2D *flgr2d_create_fgUINT32(int size_y, int size_x, int spp, FLGR_Shape shape, FLGR_Connexity connexity) {
  FLGR_MACRO_CREATE2D(fgUINT32, FLGR_UINT32);
}
FLGR_Data2D *flgr2d_create_fgINT8(int size_y, int size_x, int spp, FLGR_Shape shape, FLGR_Connexity connexity) {
  FLGR_MACRO_CREATE2D(fgINT8, FLGR_INT8);
}
FLGR_Data2D *flgr2d_create_fgINT16(int size_y, int size_x, int spp, FLGR_Shape shape, FLGR_Connexity connexity) {
  FLGR_MACRO_CREATE2D(fgINT16, FLGR_INT16);
}
FLGR_Data2D *flgr2d_create_fgINT32(int size_y, int size_x, int spp, FLGR_Shape shape, FLGR_Connexity connexity) {
  FLGR_MACRO_CREATE2D(fgINT32, FLGR_INT32);
}
FLGR_Data2D *flgr2d_create_fgFLOAT32(int size_y, int size_x, int spp, FLGR_Shape shape, FLGR_Connexity connexity) {
  FLGR_MACRO_CREATE2D(fgFLOAT32, FLGR_FLOAT32);
}
FLGR_Data2D *flgr2d_create_fgFLOAT64(int size_y, int size_x, int spp, FLGR_Shape shape, FLGR_Connexity connexity) {
  FLGR_MACRO_CREATE2D(fgFLOAT64, FLGR_FLOAT64);
}

FLGR_Data2D *flgr2d_create(int size_y, int size_x, int spp, FLGR_Type type, FLGR_Shape shape, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;

  if(type==FLGR_BIT)     return flgr2d_create_fgBIT(size_y, size_x, spp, shape, connexity);
  if(type==FLGR_UINT8)   return flgr2d_create_fgUINT8(size_y, size_x, spp, shape, connexity);
  if(type==FLGR_UINT16)  return flgr2d_create_fgUINT16(size_y, size_x, spp, shape, connexity);
  if(type==FLGR_UINT32)  return flgr2d_create_fgUINT32(size_y, size_x, spp, shape, connexity);
  if(type==FLGR_INT8)    return flgr2d_create_fgINT8(size_y, size_x, spp, shape, connexity);
  if(type==FLGR_INT16)   return flgr2d_create_fgINT16(size_y, size_x, spp, shape, connexity);
  if(type==FLGR_INT32)   return flgr2d_create_fgINT32(size_y, size_x, spp, shape, connexity);
  if(type==FLGR_FLOAT32) return flgr2d_create_fgFLOAT32(size_y, size_x, spp, shape, connexity);
  if(type==FLGR_FLOAT64) return flgr2d_create_fgFLOAT64(size_y, size_x, spp, shape, connexity);

  POST_ERROR("Type unknown!\n");
  return NULL;

}

FLGR_Data2D *flgr2d_create_from(FLGR_Data2D *datsrc) {
  FLGR_DECLARE_FUNCTION;

  if(datsrc==NULL) {
    POST_ERROR("Null objects!\n");
    return NULL;
  }
  return flgr2d_create(datsrc->size_y,datsrc->size_x,datsrc->spp,datsrc->type,datsrc->shape,datsrc->connexity);
}


//////////////////////////////////////////////////////////////////
/*! Allocate a FLGR_Data2D structure representing an image
 *  @param size_y    : an integer for array size_y
 *  @param size_x    : an integer for array size_x
 *  @param spp       : Samples per pixel
 *  @param type      : a string for data type (FLGR_UINT8, FLGR_UINT16, FLGR_UINT32, FLGR_INT8, FLGR_INT16, FLGR_INT32, FLGR_FLOAT32, FLGR_FLOAT64)
 *  @returns FLGR_Data2D pointer
 */
//////////////////////////////////////////////////////////////////
FLGR_Data2D *flgr2d_create_pixmap(int size_y, int size_x, int spp, FLGR_Type type) {
  FLGR_DECLARE_FUNCTION;

  return flgr2d_create(size_y, size_x, spp, type, FLGR_NO_SHAPE, FLGR_NO_CONNEX);
}

//////////////////////////////////////////////////////////////////
/*! Allocate a FLGR_Data2D structure by copying size and type from another FLGR_Data2D. Image contents is not copied
 *  @param imgsrc : a pointer to FLGR_Data2D
 *  @returns FLGR_Data2D
 */
//////////////////////////////////////////////////////////////////
FLGR_Data2D *flgr2d_create_pixmap_from(FLGR_Data2D *imgsrc) {
  FLGR_DECLARE_FUNCTION;

  if(imgsrc==NULL) {
    POST_ERROR("Null objects!\n");
    return NULL;
  }
  return flgr2d_create(imgsrc->size_y, imgsrc->size_x, imgsrc->spp, imgsrc->type, FLGR_NO_SHAPE, FLGR_NO_CONNEX);
}

//////////////////////////////////////////////////////////////////
/*! Allocate a FLGR_Data2D structure representing a Neighborhood definition
 *  @param size_y    : an integer for array size_y
 *  @param size_x    : an integer for array size_x
 *  @param spp       : Samples per pixel
 *  @param type      : a string for data type (FLGR_UINT8, FLGR_UINT16, FLGR_UINT32, FLGR_INT8, FLGR_INT16, FLGR_INT32, FLGR_FLOAT32, FLGR_FLOAT64)
 *  @param shape     : a string for shape considered (FLGR_RECT, FLGR_HEX, FLGR_DISC, "SLASH", "BSLASH", FLGR_CROSS, "CROSS2")
 *  @param connexity :
 *  @returns FLGR_Data2D pointer
 */
//////////////////////////////////////////////////////////////////
FLGR_Data2D *flgr2d_create_neighborhood(int size_y, int size_x, int spp, FLGR_Type type,
					FLGR_Shape shape, FLGR_Connexity connexity) {
  FLGR_Data2D *nhb;

  FLGR_DECLARE_FUNCTION;

  if((size_x%2)==0) {
    POST_WARNING("Warning NhbWidth(%d) is even! Changing to the next odd value (%d) \n", size_x, size_x+1);
    size_x++;
  }
  if((size_y%2)==0) {
    POST_WARNING("Warning NhbWidth(%d) is even! Changing to the next odd value (%d) \n", size_y, size_y+1);
    size_y++;
  }

  if( (connexity != FLGR_4_CONNEX) && (connexity != FLGR_6_CONNEX) && (connexity != FLGR_8_CONNEX)) {
    POST_ERROR("bad connexity : %d\n", connexity);
    return NULL;
  }

  if((nhb=flgr2d_create(size_y, size_x, spp, type, shape, connexity))==NULL) return NULL;

  if(flgr2d_fill_neighborhood(nhb, shape, size_x,size_y)!=FLGR_RET_OK) {
    flgr2d_destroy(nhb);
    return NULL;
  }

  return nhb;

}

//////////////////////////////////////////////////////////////////
/*! Allocate a FLGR_Data2D structure by copying size, type, shape and connexity from another FLGR_Data2D.
 *  Neighborhood definition contents is not copied, but created from collected informations.
 *  @param nhbsrc : a pointer to FLGR_Data2D
 *  @returns FLGR_Data2D pointer
 */
//////////////////////////////////////////////////////////////////
FLGR_Data2D *flgr2d_create_neighborhood_from(FLGR_Data2D *nhbsrc) {
  FLGR_DECLARE_FUNCTION;

  if(nhbsrc==NULL) {
    POST_ERROR("Null objects!\n");
    return NULL;
  }
  return flgr2d_create_neighborhood(nhbsrc->size_y, nhbsrc->size_x, nhbsrc->spp,
				    nhbsrc->type, nhbsrc->shape, nhbsrc->connexity);
}

//////////////////////////////////////////////////////////////////
/*! Allocate a FLGR_Data2D structure only with connexity information. The size is the smallest for the connexity specified
 *  @param spp       : Samples per pixel
 *  @param type
 *  @param connexity
 *  @returns FLGR_Data2D pointer
 */
//////////////////////////////////////////////////////////////////
FLGR_Data2D *flgr2d_create_neighborhood_from_connexity(int spp, FLGR_Type type, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;

  switch(connexity) {
  case FLGR_8_CONNEX:
    return flgr2d_create_neighborhood(3, 3, spp, type, FLGR_RECT, FLGR_8_CONNEX);

  case FLGR_6_CONNEX:
    return flgr2d_create_neighborhood(3, 3, spp, type, FLGR_HEX, FLGR_6_CONNEX);

  case FLGR_4_CONNEX:
    return flgr2d_create_neighborhood(3, 3, spp, type, FLGR_CROSS, FLGR_4_CONNEX);

  default:
    POST_ERROR("bad connexity : %d\n", connexity);
    return NULL;
  }
}


//////////////////////////////////////////////////////////////////
/*! Unallocate a FLGR_Data2D structure
 *  @param dat : a pointer to FLGR_Data2D
 *  @returns
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_destroy(FLGR_Data2D *dat) {
  int i;

  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(dat->link_overlap > -1) {
    POST_WARNING("Destroying a linked data, branching to flgr2d_destroy_link\n");
    return flgr2d_destroy_link(dat);
  }

  for(i=0 ; i<dat->size_y+16 ; i++) {
    flgr1d_destroy(dat->row[i]);
  }

  flgr_free(dat->array);
  flgr_free(dat->row);
  flgr_free(dat);

  return FLGR_RET_OK;
}



//////////////////////////////////////////////////////////////////
/*! Create an image and instead of allocating rows, copy rows pointer from another image
 *  @param datain : a pointer to FLGR_Data2D
 *  @param partsNumber : integer representing where row start link in source data
 *  @param partIndex : integer representing where row stop link in source data
 *  @param overlapSize : overlap size to consider between parts
 *  @returns a pointer to FLGR_Data2D
 */
//////////////////////////////////////////////////////////////////
FLGR_Data2D *flgr2d_create_pixmap_link(FLGR_Data2D *datain, int partsNumber, int partIndex, int overlapSize) {
  FLGR_Data2D *dat;
  int i,k,nbrow,startin;

  FLGR_DECLARE_FUNCTION;

  if(overlapSize < 0) {
    POST_ERROR("overlapSize could not be < 0 !\n");
    return NULL;
  }

  if(partsNumber < 1) {
    POST_ERROR("Number of parts must be > 0 !\n");
    return NULL;
  }

  if(partIndex >= partsNumber) {
    POST_ERROR("Index reference (%d) does not exists!\n",partIndex);
    return NULL;
  }

  if(partIndex < 0) {
    POST_ERROR("Index reference (%d) does not exists!\n",partIndex);
    return NULL;
  }

  dat                = (FLGR_Data2D*) flgr_malloc(sizeof(FLGR_Data2D));
  dat->link_overlap  = overlapSize;
  dat->link_position = partIndex;
  dat->link_number   = partsNumber;
  dat->dim           = 2;
  dat->size_struct   = sizeof(FLGR_Data2D);
  dat->bps           = datain->bps;
  dat->spp           = datain->spp;
  dat->shape         = FLGR_NO_SHAPE;
  dat->connexity     = FLGR_NO_CONNEX;
  dat->size_x        = datain->size_x;
  dat->type          = datain->type;

  startin = (datain->size_y * partIndex) / partsNumber;
  
  if(partIndex == 0) { /* row links of the first Part */
    nbrow = datain->size_y/partsNumber + overlapSize;

    dat->row    = (FLGR_Data1D**) flgr_malloc( (nbrow+16) * sizeof(FLGR_Data1D*));
    dat->array  = flgr_malloc( (nbrow+16) * sizeof(void*));
    dat->size_y = nbrow;

    for(i=0 ; i<nbrow-overlapSize ; i++) {
      dat->row[i] = datain->row[i];
      dat->row[i]->ref2d = i;
      dat->array[i] = dat->row[i]->array;
    }

    for(i=nbrow-overlapSize ; i<nbrow ; i++) {
      dat->row[i]        = flgr1d_create(dat->size_x, dat->spp, dat->type, FLGR_NO_SHAPE);
      dat->row[i]->ref2d = i;
      dat->array[i]      = dat->row[i]->array;
      flgr1d_copy(dat->row[i],datain->row[i]);
    }

    for(i=nbrow ; i<nbrow+16 ; i++) {
      dat->row[i] = flgr1d_create(dat->size_x, dat->spp, dat->type, FLGR_NO_SHAPE);
      dat->row[i]->ref2d = i;
      dat->array[i] = dat->row[i]->array;
    }




  }else if(partIndex == (partsNumber-1)) { /* row links of the last Part*/
    nbrow = datain->size_y/partsNumber + overlapSize;

    dat->row    = (FLGR_Data1D**) flgr_malloc( (nbrow+16) * sizeof(FLGR_Data1D*));
    dat->array  = flgr_malloc( (nbrow+16) * sizeof(void*));
    dat->size_y = nbrow;

    i = startin-overlapSize;
    k=0;

    for( ; k<overlapSize ; i++,k++) {
      dat->row[k]        = flgr1d_create(dat->size_x, dat->spp, dat->type, FLGR_NO_SHAPE);
      dat->row[k]->ref2d = k;
      dat->array[k]      = dat->row[k]->array;
      flgr1d_copy(dat->row[k],datain->row[i]);
    }

    for( ; k<nbrow ; i++,k++) {
      dat->row[k] = datain->row[i];
      dat->row[k]->ref2d = k;
      dat->array[k] = dat->row[k]->array;
    }

    for( ; k<nbrow+16  ; k++) {
      dat->row[k]        = flgr1d_create(dat->size_x, dat->spp, dat->type, FLGR_NO_SHAPE);
      dat->row[k]->ref2d = k;
      dat->array[k]      = dat->row[k]->array;
    }






  }else { /* row links of all others parts */
    nbrow = datain->size_y/partsNumber + 2*overlapSize;

    dat->row    = (FLGR_Data1D**) flgr_malloc( (nbrow+16) * sizeof(FLGR_Data1D*));
    dat->array  = flgr_malloc( (nbrow+16) * sizeof(void*));
    dat->size_y = nbrow;

    i = startin-overlapSize;
    k=0;

    for( ; k<overlapSize ; i++,k++) {
      dat->row[k]        = flgr1d_create(dat->size_x, dat->spp, dat->type, FLGR_NO_SHAPE);
      dat->row[k]->ref2d = k;
      dat->array[k]      = dat->row[k]->array;
      flgr1d_copy(dat->row[k],datain->row[i]);
    }

    for( ; k<nbrow-overlapSize ; i++,k++) {
      dat->row[k] = datain->row[i];
      dat->row[k]->ref2d = k;
      dat->array[k] = dat->row[k]->array;
    }

    for( ; k<nbrow  ; i++,k++) {
      dat->row[k]        = flgr1d_create(dat->size_x, dat->spp, dat->type, FLGR_NO_SHAPE);
      dat->row[k]->ref2d = k;
      dat->array[k]      = dat->row[k]->array;
      flgr1d_copy(dat->row[k],datain->row[i]);
    }

    for( ; k<nbrow+16  ; k++) {
      dat->row[k]        = flgr1d_create(dat->size_x, dat->spp, dat->type, FLGR_NO_SHAPE);
      dat->row[k]->ref2d = k;
      dat->array[k]      = dat->row[k]->array;
    }

  }
 
 

  return dat;
}


//////////////////////////////////////////////////////////////////
/*! Unallocate a FLGR_Data2D which is a link another FLGR_Data2D
 *  @param dat : a pointer to FLGR_Data2D
 *  @returns
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_destroy_link(FLGR_Data2D *dat) {
  int k;

  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(dat->link_overlap == -1) {
    POST_WARNING("Destroying a non-linked data, branching to flgr2d_destroy\n");
    return flgr2d_destroy(dat);
  }

  if(dat->link_position == 0) {
    for(k=dat->size_y-dat->link_overlap ; k<dat->size_y+16 ; k++) {
      flgr1d_destroy(dat->row[k]);
    }

  }else if( dat->link_position == (dat->link_number - 1)  ) {
    for(k=0 ; k<dat->link_overlap ; k++) {
      flgr1d_destroy(dat->row[k]);
    }
    
    for(k=dat->size_y ; k<dat->size_y+16 ; k++) {
      flgr1d_destroy(dat->row[k]);
    }
    
   }else {
    for(k=0 ; k<dat->link_overlap ; k++) {
      flgr1d_destroy(dat->row[k]);
    }
    for(k=dat->size_y-dat->link_overlap ; k<dat->size_y+16 ; k++) {
      flgr1d_destroy(dat->row[k]);
    }
  }

  flgr_free(dat->array);
  flgr_free(dat->row);
  flgr_free(dat);

  return FLGR_RET_OK;
}



//////////////////////////////////////////////////////////////////
/*! Test if two FLGR_Data2D have the same type
 *  @param data1 : a pointer to FLGR_Data2D
 *  @param data2 : a pointer to FLGR_Data2D
 *  @returns FLGR_RET_OK, FLGR_RET_TYPE_UNKNOWN, FLGR_RET_TYPE_DIFFERENT
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_is_data_same_type(FLGR_Data2D *data1, FLGR_Data2D *data2) {
  FLGR_Ret ret;
  FLGR_DECLARE_FUNCTION;


  if((data1==NULL) || (data2==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if( (ret=flgr_is_data_type_valid(data1->type)) != FLGR_RET_OK ) return ret;
  if( (ret=flgr_is_data_type_valid(data2->type)) != FLGR_RET_OK ) return ret;

  if(data1->type != data2->type) {
    return FLGR_RET_TYPE_DIFFERENT;
  }

  return FLGR_RET_OK;
}

//////////////////////////////////////////////////////////////////
/*! Test if data2d have same samples per pixel. 
 *  Valid spp check is also performed
 *  @param dat1 : a pointer to FLGR_Data2D
 *  @param dat2 : a pointer to FLGR_Data2D
 *  @returns Return FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_is_data_same_spp(FLGR_Data2D *dat1, FLGR_Data2D *dat2) {
  FLGR_DECLARE_FUNCTION;

  if((dat1==NULL) || (dat2==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }


  if(dat1->spp <0) return  FLGR_RET_VECTOR_SIZE_DIFFERENT;
  if(dat2->spp <0) return FLGR_RET_VECTOR_SIZE_DIFFERENT;

  if(dat1->spp != dat2->spp) return FLGR_RET_VECTOR_SIZE_DIFFERENT;

  return FLGR_RET_OK;
}

//////////////////////////////////////////////////////////////////
/*! Test if two FLGR_Data2D have the same sizes (size_x and size_y)
 *  @param data1 : a pointer to FLGR_Data2D
 *  @param data2 : a pointer to FLGR_Data2D
 *  @returns FLGR_RET_OK, FLGR_RET_SIZE_ERROR
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_is_data_same_size(FLGR_Data2D *data1, FLGR_Data2D *data2) {

  FLGR_DECLARE_FUNCTION;

  if((data1==NULL) || (data2==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((data1->size_y!=data2->size_y)||(data1->size_x!=data2->size_x)) {
    return FLGR_RET_SIZE_ERROR;
  }

  return FLGR_RET_OK;
}

//////////////////////////////////////////////////////////////////
/*! Test if two FLGR_Data2D have the same sizes and same types
 *  @param data1 : a pointer to FLGR_Data2D
 *  @param data2 : a pointer to FLGR_Data2D
 *  @param callingFunction : String representing the name of the calling function
 *  @returns FLGR_RET_OK, FLGR_RET_SIZE_ERROR
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_is_data_same_attributes(FLGR_Data2D *data1, FLGR_Data2D *data2, const char *callingFunction) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((data1==NULL) || (data2==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if( (ret=flgr_is_data_type_valid(data1->type))!=FLGR_RET_OK) {
    EPRINTF("%s: unknown type\r\n", callingFunction);
    return ret;
  }

  if( (ret=flgr_is_data_type_valid(data2->type))!=FLGR_RET_OK) {
    EPRINTF("%s: unknown type\r\n", callingFunction);
    return ret;
  }

  if((ret=flgr2d_is_data_same_type(data1, data2))!=FLGR_RET_OK) {
    EPRINTF("%s : source and destination have a different type\r\n", callingFunction);
    return ret;
  }

  if((ret=flgr2d_is_data_same_spp(data1, data2))!=FLGR_RET_OK) {
    EPRINTF("%s : source and destination have a different vector size(spp)\r\n", callingFunction);
    return ret;
  }

  if((data1->size_y!=data2->size_y)||(data1->size_x!=data2->size_x)) {
    EPRINTF("%s : source and destination have a different size\r\n", callingFunction);
    return FLGR_RET_SIZE_ERROR;
  }

  return FLGR_RET_OK;
}




//////////////////////////////////////////////////////////////////
/*! Test if a FLGR_Data2D correspond to a given shape
 *  @param data : a pointer to FLGR_Data2D
 *  @param shape : shape flag
 *  @returns boolean
 */
//////////////////////////////////////////////////////////////////
int flgr2d_data_is_shape(FLGR_Data2D *data, FLGR_Shape shape) {
  FLGR_DECLARE_FUNCTION;

  if(data==NULL) {
    POST_ERROR("Null objects!\n");
    return 0;
  }

  return (data->shape==shape);
}

//////////////////////////////////////////////////////////////////
/*! Test if a FLGR_Data2D correspond to a connexity
 *  @param data : a pointer to FLGR_Data2D
 *  @param connexity : connexity flag
 *  @returns boolean
 */
//////////////////////////////////////////////////////////////////
int flgr2d_data_is_connexity(FLGR_Data2D *data, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;

  if(data==NULL) {
    POST_ERROR("Null objects!\n");
    return 0;
  }

  return (data->connexity==connexity);
}

int flgr2d_data_is_type_fgBIT(FLGR_Data2D *data) {
  return (data->type==FLGR_BIT);
}
int flgr2d_data_is_type_fgUINT8(FLGR_Data2D *data) {
  return (data->type==FLGR_UINT8);
}
int flgr2d_data_is_type_fgUINT16(FLGR_Data2D *data) {
  return (data->type==FLGR_UINT16);
}
int flgr2d_data_is_type_fgUINT32(FLGR_Data2D *data) {
  return (data->type==FLGR_UINT32);
}
int flgr2d_data_is_type_fgINT8(FLGR_Data2D *data) {
  return (data->type==FLGR_INT8);
}
int flgr2d_data_is_type_fgINT16(FLGR_Data2D *data) {
  return (data->type==FLGR_INT16);
}
int flgr2d_data_is_type_fgINT32(FLGR_Data2D *data) {
  return (data->type==FLGR_INT32);
}
int flgr2d_data_is_type_fgFLOAT32(FLGR_Data2D *data) {
  return (data->type==FLGR_FLOAT32);
}
int flgr2d_data_is_type_fgFLOAT64(FLGR_Data2D *data) {
  return (data->type==FLGR_FLOAT64);
}

//////////////////////////////////////////////////////////////////
/*! Test if a FLGR_Data2D correspond to a given type
 *  @param data : a pointer to FLGR_Data2D
 *  @param type : type
 *  @returns boolean
 */
//////////////////////////////////////////////////////////////////
int flgr2d_data_is_type(FLGR_Data2D *data, FLGR_Type type) {
  FLGR_DECLARE_FUNCTION;

  if(data==NULL) {
    POST_ERROR("Null objects!\n");
    return 0;
  }

  FLGR_DISPATCH_FUNCTION(FLGR_FALSE,type,flgr2d_data_is_type,data);
}

//////////////////////////////////////////////////////////////////
/*! Change the shape string of a FLGR_Data2D (No modification of neighborhood definition or pixel array)
 *  @param dat : a pointer to FLGR_Data2D
 *  @param shape : a string for shape
 *  @returns nothing
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_data_set_shape(FLGR_Data2D *dat, FLGR_Shape shape) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return 0;
  }

  dat->shape = shape;

  return FLGR_RET_OK;
}

//////////////////////////////////////////////////////////////////
/*! Change the connexity of a FLGR_Data2D
 *  @param dat : a pointer to FLGR_Data2D
 *  @param connexity : FLGR_Connexity connexity
 *  @returns nothing
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_data_set_connexity(FLGR_Data2D *dat, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return 0;
  }

  dat->connexity = connexity;
  return FLGR_RET_OK;
}


//////////////////////////////////////////////////////////////////
/*! Set to zero the whole image
 *  @param data : a pointer to a FLGR_Data2D
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_clear_all(FLGR_Data2D *data) {
  int i;

  FLGR_DECLARE_FUNCTION;

  if(data==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }


  for(i=0 ; i<data->size_y ; i++) flgr1d_clear_all(data->row[i]);

  return FLGR_RET_OK;
}


//! @}

